// thread-per-message.cpp


#include <csignal>
#include <cstdio>
#include <cstdlib>

#include <chrono>
#include <future>
#include <thread>


namespace blogs
{


using std::chrono::milliseconds;
using std::future;
using std::launch;
using std::thread;


class Helper
{

  public:

    void
    handle(int count, char c)
    {
        std::printf("   handle(%d, %c) BEGIN\n", count, c);
        for (int i = 0; i < count; ++i) {
            std::this_thread::sleep_for(milliseconds(100));
            std::printf("%c", c);
        }
        std::printf("   handle(%d, %c) END\n", count, c);
    }

};


class Host
{

  private:

    Helper
    __helper__;


  public:

    Host()
        : __helper__()
    {
    }


    /*
     * -- (1) --
     * transfer the ownership of the thread to the caller.
     */
    thread
    request(int count, char c)
    {
        std::printf("   request(%d, %c) BEGIN\n", count, c);
        thread t([this, count, c] {
            __helper__.handle(count, c);
        });
        std::printf("   request(%d, %c) END\n", count, c);
        return t;
    }


    /*
     * -- (2) --
     * async task with future
     */
    //future<void> request(int count, char c)
    //{
    //    std::printf("   request(%d, %c) BEGIN\n", count, c);
    //    future<void> f = std::async(launch::async, [=] {
    //                                    __helper__.handle(count, c);
    //                                });
    //    std::printf("   request(%d, %c) END\n", count, c);
    //    return f;
    //}

};


void
bye(int sig = SIGTERM)
{
    std::printf("\nBye Thread-Per-Message...\n\n");
    std::exit(sig);
}


} // end of namespace blogs


int main() {
    using std::thread;
    using std::future;
    using blogs::Helper;
    using blogs::Host;

    std::signal(SIGINT, blogs::bye);

    std::printf("main BEGIN\n");

    Host host;

    // -- (1) --
    thread t1 = host.request(30, 'A');
    thread t2 = host.request(40, 'B');
    thread t3 = host.request(50, 'C');

    // -- (2) --
    //future<void> f1 = host.request(30, 'A');
    //future<void> f2 = host.request(40, 'B');
    //future<void> f3 = host.request(50, 'C');

    std::printf("main END\n");

    // -- (1) --
    t1.join();
    t2.join();
    t3.join();

    // -- (2) --
    //f1.get();
    //f2.get();
    //f3.get();

    blogs::bye();
    return 0;
}

